package cn.sofwin.core.utils.security.up;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FilenameFilter;
import java.io.IOException;
import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.PrivateKey;
import java.security.Provider;
import java.security.PublicKey;
import java.security.Security;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.spec.RSAPublicKeySpec;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

/**
 * 银联证书工具类
 * @author LetCode
 * @since 1.0
 *
 */
public class CertUtil {

	public static Map<String, X509Certificate> getValidateCertMapFromFolder(String validateCertFolder) {
		LogUtil.writeLog("从目录中加载验证签名证书开始.");
		Map<String, X509Certificate> certMap = new HashMap<>();

		X509Certificate validateCert = null;
		CertificateFactory cf = null;
		FileInputStream in = null;
		try {
			cf = CertificateFactory.getInstance("X.509");
			File fileDir = new File(validateCertFolder);
			File[] files = fileDir.listFiles(new CerFilter());
			for (int i = 0; i < files.length; i++) {
				File file = files[i];
				in = new FileInputStream(file.getAbsolutePath());
				validateCert = (X509Certificate) cf.generateCertificate(in);
				certMap.put(validateCert.getSerialNumber().toString(), validateCert);

				LogUtil.writeLog("[" + file.getAbsolutePath() + "][serialNumber=" + validateCert.getSerialNumber().toString() + "]");
			}

			if (null != in) {
				try {
					in.close();
				} catch (IOException e) {
					LogUtil.writeErrorLog(e.toString());
				}
			}

			LogUtil.writeLog("从目录中加载验证签名证书结束.");
		} catch (CertificateException e) {
			LogUtil.writeErrorLog("验证签名证书加载失败", e);
		} catch (FileNotFoundException e) {
			LogUtil.writeErrorLog("验证签名证书加载失败,证书文件不存在", e);
		} finally {
			if (null != in) {
				try {
					in.close();
				} catch (IOException e) {
					LogUtil.writeErrorLog(e.toString());
				}
			}
		}
		
		return certMap;
	}

	public static PrivateKey getSignCertPrivateKey(KeyStore mchKeyStore, String certPwd) {
		try {
			Enumeration<String> aliasenum = mchKeyStore.aliases();
			String keyAlias = null;
			if (aliasenum.hasMoreElements()) {
				keyAlias = (String) aliasenum.nextElement();
			}
			return (PrivateKey) mchKeyStore.getKey(keyAlias, certPwd.toCharArray());
		} catch (Exception e) {
			LogUtil.writeErrorLog("获取签名证书的私钥失败", e);
		}
		return null;
	}

	public static PublicKey getValidateKey(Map<String, X509Certificate> certMap, String certId) {
		X509Certificate cf = null;
		if (certMap.containsKey(certId)) {
			cf = (X509Certificate) certMap.get(certId);
			return cf.getPublicKey();
		}
		LogUtil.writeErrorLog("缺少certId=[" + certId + "]对应的验签证书文件.");
		return null;
	}

	public static String getSignCertId(KeyStore keyStore) {
		try {
			Enumeration<String> aliasenum = keyStore.aliases();
			String keyAlias = null;
			if (aliasenum.hasMoreElements()) {
				keyAlias = (String) aliasenum.nextElement();
			}
			X509Certificate cert = (X509Certificate) keyStore.getCertificate(keyAlias);

			return cert.getSerialNumber().toString();
		} catch (Exception e) {
			LogUtil.writeErrorLog("获取签名证书的序列号失败", e);
			if (null == keyStore)
				LogUtil.writeErrorLog("keyStore实例化失败,当前为NULL");
		}
		return "";
	}


	public static PublicKey getSignPublicKey(KeyStore keyStore) {
		try {
			Enumeration<String> aliasenum = keyStore.aliases();
			String keyAlias = null;
			if (aliasenum.hasMoreElements()) {

				keyAlias = (String) aliasenum.nextElement();
			}

			Certificate cert = keyStore.getCertificate(keyAlias);
			return cert.getPublicKey();
		} catch (Exception e) {
			LogUtil.writeErrorLog(e.toString());
		}
		return null;
	}

	public static KeyStore getKeyInfo(String pfxkeyfile, String keypwd, String type) throws IOException {
		FileInputStream fis = null;
		try {
			KeyStore ks = null;
			if ("JKS".equals(type)) {
				ks = KeyStore.getInstance(type);
			} else if ("PKCS12".equals(type)) {
				String jdkVendor = System.getProperty("java.vm.vendor");
				LogUtil.writeLog("java.vm.vendor=[" + jdkVendor + "]");

				if ((null != jdkVendor) && (jdkVendor.startsWith("IBM"))) {
					Security.insertProviderAt(new BouncyCastleProvider(), 1);

					printSysInfo();
				} else {
					Security.addProvider(new BouncyCastleProvider());
				}

				ks = KeyStore.getInstance(type);
			}
			LogUtil.writeLog("传入的私钥证书路径为=>[" + pfxkeyfile + "],密码=[" + keypwd + "]");
			fis = new FileInputStream(pfxkeyfile);
			char[] nPassword = null;
			nPassword = (null == keypwd) || ("".equals(keypwd.trim())) ? null : keypwd.toCharArray();

			if (null != ks) {
				ks.load(fis, nPassword);
				LogUtil.writeLog("KeyStore Load End");
			}
			return ks;
		} catch (Exception e) {
			if (Security.getProvider("BC") == null) {
				LogUtil.writeLog("BC Provider not installed.");
			}
			LogUtil.writeErrorLog("读取私钥证书失败", e);
			if (((e instanceof KeyStoreException)) && ("PKCS12".equals(type))) {
				Security.removeProvider("BC");
			}
			return null;
		} finally {
			if (null != fis) {
				fis.close();
			}
		}
	}

	public static void printSysInfo() {
		LogUtil.writeLog("================= SYS INFO begin====================");
		LogUtil.writeLog("os_name:" + System.getProperty("os.name"));
		LogUtil.writeLog("os_arch:" + System.getProperty("os.arch"));
		LogUtil.writeLog("os_version:" + System.getProperty("os.version"));
		LogUtil.writeLog("java_vm_specification_version:" + System.getProperty("java.vm.specification.version"));

		LogUtil.writeLog("java_vm_specification_vendor:" + System.getProperty("java.vm.specification.vendor"));

		LogUtil.writeLog("java_vm_specification_name:" + System.getProperty("java.vm.specification.name"));

		LogUtil.writeLog("java_vm_version:" + System.getProperty("java.vm.version"));

		LogUtil.writeLog("java_vm_name:" + System.getProperty("java.vm.name"));
		printProviders();
		LogUtil.writeLog("================= SYS INFO end=====================");
	}

	public static void printProviders() {
		LogUtil.writeLog("Providers List:");
		Provider[] providers = Security.getProviders();
		for (int i = 0; i < providers.length; i++) {
			LogUtil.writeLog(i + 1 + "." + providers[i].getName());
		}
	}

	static class CerFilter implements FilenameFilter {
		public boolean isCer(String name) {
			if (name.toLowerCase().endsWith(".cer")) {
				return true;
			}
			return false;
		}

		public boolean accept(File dir, String name) {
			return isCer(name);
		}
	}

	public static String getCertIdByCertPath(String path, String pwd, String certTp) {
		KeyStore ks = null;
		try {
			ks = getKeyInfo(path, pwd, certTp);
		} catch (IOException e1) {
			LogUtil.writeErrorLog("加载签名证书失败", e1);
		}
		if (null == ks) {
			return "";
		}
		try {
			Enumeration<String> aliasenum = ks.aliases();
			String keyAlias = null;
			if (aliasenum.hasMoreElements()) {
				keyAlias = (String) aliasenum.nextElement();
			}
			X509Certificate cert = (X509Certificate) ks.getCertificate(keyAlias);

			return cert.getSerialNumber().toString();
		} catch (Exception e) {
			LogUtil.writeErrorLog("获取签名证书的序列号失败", e);
		}
		return "";
	}

	public static PublicKey getPublicKey(String modulus, String exponent) {
		try {
			BigInteger b1 = new BigInteger(modulus);
			BigInteger b2 = new BigInteger(exponent);
			KeyFactory keyFactory = KeyFactory.getInstance("RSA");
			RSAPublicKeySpec keySpec = new RSAPublicKeySpec(b1, b2);
			return keyFactory.generatePublic(keySpec);
		} catch (Exception e) {
			LogUtil.writeErrorLog("构造RSA公钥失败：" + e);
		}
		return null;
	}

	public static PublicKey getEncryptTrackCertPublicKey(String modulus, String exponent) {
		if ((SDKUtil.isEmpty(modulus)) || (SDKUtil.isEmpty(exponent))) {
			LogUtil.writeErrorLog("[modulus][exponent]无效");
			return null;
		}
		return getPublicKey(modulus, exponent);
	}
}